import Glibc
class Timer {
    private let CLOCK_REALTIME = 0
    private var start_timespec = timespec()
    private var end_timespec = timespec()
    private var time_spec = timespec()
    func start() {
        clock_gettime(Int32(CLOCK_REALTIME),&start_timespec)
    }
    
    func stop() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&end_timespec)
        let start_time = Double(start_timespec.tv_sec * 1_000_000 + start_timespec.tv_nsec / 1_000)
        let end_time = Double(end_timespec.tv_sec * 1_000_000 + end_timespec.tv_nsec / 1_000)
        let time = end_time - start_time
        return time / 1_000
    }
    func getTime() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&time_spec)
        return Double(time_spec.tv_sec * 1_000_000 + time_spec.tv_nsec / 1_000)
    }
}
func GenerateRandoms() -> [Int]{
    let result = Array(repeating: Int.random(in: 1..<3), count: 2)
    return result
}
var generaterandoms = GenerateRandoms()

func TimeGenerateRandoms() -> Double{
    let timer = Timer()
    timer.start()
    let tmp = 1
    if generaterandoms[tmp%2] != 0 {

    }
	let time = timer.stop()
    return time
}
class Obj {
    var value: Int = 0
    init(value: Int) {
        self.value = value
    }
}

func GenerateFakeRandomObject() -> [Obj] {
    let resource: [Obj] = [Obj](repeating: Obj(value: Int.random(in: 1..<10)), count: 15)
    return resource
}
var global = 0
func GenerateFakeRandomInteger() -> [Int] {
    let resource: [Int] = [12, 43, 56, 76, 89, 54, 45, 32, 35, 47, 46, 44, 21, 37, 84]
    return resource;
}

var arr : [Int] = GenerateFakeRandomInteger()

class ClassFunc {
    func foo(resources: [Int], i: Int, i3: Int, resourcesLength: Int) ->Int {
        var i4 = i3;
        if ((resources[i % Int(i3) & (resourcesLength - 1)] & 1) == 0) {
            i4 += 1;
        } else {
            i4 += 2;
        }
        return i4;
    }
    func parameterlessFoo() -> Obj {
        var res: [Obj] = [Obj](repeating: Obj(value: Int.random(in: 1..<10)), count: 5)
        let resources = GenerateFakeRandomObject()
        for i in 0..<200 {
            res[i % 5] = resources[i % 15]
        }
        return res[1]
    }
    func differentFoo(_ resources: [Int], _ i: Int, _ i3: Double, _ resourcesLength: Int) -> Double {
        var i4 = i3;
        if ((resources[i % Int(i3) & (resourcesLength - 1)] & 1) == 0) {
            i4 += 1.1;
        } else {
            i4 += 2.1;
        }
        return i4;
    }
    func defaultFoo(_ resources: [Int]! = arr, _ i: Int! = 2, _ i3: Int! = 1, _ resourcesLength: Int! = 15) -> Int {
        var i4 = 1;
        if ((resources[i % Int(i3) & (resourcesLength - 1)] & 1) == 0) {
            i4 += 1;
        } else {
            i4 += 2;
        }
        return i4;
    }
    func variableFoo(_ a: Int? = nil, _ b: String? = nil, _ c: Bool? = nil) {
        arr[global] += 1
    }
    func argsFoo(_ args: Int...) {
        global += 1
    }
    var member: Int = Int.random(in: 1..<3);
    var resources: [Int] = GenerateFakeRandomInteger()
}
/***************** With parameters *****************/
// Method call

func RunMethodCall() -> Int {
    let count = 10000000
    let cf = ClassFunc()
    let timer = Timer()
    let resources = GenerateFakeRandomInteger();
    var i3 = 1
    let func1:([Int], Int, Int, Int) -> Int = cf.foo
    let resourcesLength = resources.count
    let startTime = timer.getTime()
    for i in 0..<count {
        i3 = func1(resources, i, i3, resourcesLength)
    }
    let midTime = timer.getTime()
    for _ in 0..<count {
    }
    let endTime = timer.getTime()
    let time = ((midTime - startTime) - (endTime - midTime)) / 1_000
    print("Function Call - RunMethodCall:\t"+String(time)+"\tms");
    return Int(time)
}
_ = RunMethodCall()

func RunParameterlessMethodCall() -> Obj {
    let count = 10000
    let cf = ClassFunc()
    var i3 = Obj(value:1)
    let timer = Timer()
    global = 0
    let func1: () -> Obj = cf.parameterlessFoo
    let startTime = timer.getTime()
    for _ in 0..<count {
        i3 = func1()
    }
    let midTime = timer.getTime()
    for _ in 0..<count {
    }
    let endTime = timer.getTime()
    let time = ((midTime - startTime) - (endTime - midTime)) / 1_000
    print("Function Call - RunParameterlessMethodCall:\t"+String(time)+"\tms");
    return i3
}
_ = RunParameterlessMethodCall()
/***************************** Default  parameters *****************************/
// Method call
func RunDefMethodCall() -> Int {
    let count = 10000000
    let cf = ClassFunc()
    let timer = Timer()
    var i3 = 1
    let resources = GenerateFakeRandomInteger();
    let resourcesLength = resources.count
    global = 0
    let func1: ([Int]?, Int?, Int?, Int?) -> Int = cf.defaultFoo
    let startTime = timer.getTime()
    for i in 0..<count {
        i3 = func1(resources, i, i3, resourcesLength)
    }
    let midTime = timer.getTime()
    for _ in 0..<count {
    }
    let endTime = timer.getTime()
    let time = ((midTime - startTime) - (endTime - midTime)) / 1_000
    print("Function Call - RunDefMethodCall:\t"+String(time)+"\tms");
    return Int(time)
}
_ = RunDefMethodCall()
/********************* Different  parameters *********************/
// Method call
func RunDifMethodCall() -> Int {
    let count = 10000000
    let cf = ClassFunc()
    let timer = Timer()
    let resources = GenerateFakeRandomInteger();
    let resourcesLength = resources.count
    var i3 = 1.1
    global = 0
    let func1:([Int], Int, Double, Int) -> Double = cf.differentFoo
    let startTime = timer.getTime()
    for i in 0..<count {
        i3 = func1(resources, i, i3, resourcesLength)
    }
    let midTime = timer.getTime()
    for _ in 0..<count {
    }
    let endTime = timer.getTime()
    let time = ((midTime - startTime) - (endTime - midTime)) / 1_000
    print("Function Call - RunDifMethodCall:\t"+String(time)+"\tms");
    return Int(time)
}
_ = RunDifMethodCall()
/************************* Variable  parameters *************************/
// Method call
func RunVariableMethodCall() -> Int {
    let count = 10000000
    let cf = ClassFunc()
    let timer = Timer()
    global = 0
    let func1:(Int?, String?, Bool?) -> () = cf.variableFoo
    let startTime = timer.getTime()
    for _ in 0..<count {
        func1(1, "1", true)
    }
    let midTime = timer.getTime()
    for _ in 0..<count {
    }
    let endTime = timer.getTime()
    let time = ((midTime - startTime) - (endTime - midTime)) / 1_000
    print("Function Call - RunVariableMethodCall:\t"+String(time)+"\tms");
    return Int(time)
}
_ = RunVariableMethodCall()

print("Swift Method Call Is End, global value : \(global)")